package com.usian.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.usian.model.behavior.pojos.ApBehaviorEntry;
import com.usian.model.common.dtos.ResponseResult;
import com.usian.model.common.enums.AppHttpCodeEnum;
import com.usian.model.search.dtos.UserSearchDto;
import com.usian.model.search.pojos.ApUserSearch;
import com.usian.model.user.pojos.ApUser;
import com.usian.search.feiign.BehaviorFeign;
import com.usian.search.mapper.ApUserSearchMapper;
import com.usian.search.service.SearchService;
import com.usian.utils.threadlocal.AppThreadLocalUtils;
import io.swagger.models.auth.In;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl  extends ServiceImpl<ApUserSearchMapper, ApUserSearch> implements SearchService {


    @Autowired
    public RestHighLevelClient restHighLevelClient;

    @Autowired
    private BehaviorFeign behaviorFeign;

    /***
     * 文章查询
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto dto) {
        //校验参数
        if (dto == null || dto.getMinBehotTime() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //获取本地线程中的用户user
        ApUser user = AppThreadLocalUtils.getUser();
        if (user==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"先去登录");
        }
        //远程调用 behavior 获取entryId
        ApBehaviorEntry behaviorEntry = behaviorFeign.findByUserIdOrEquipmentId(user.getId(), dto.getEquipmentId());
        if (behaviorEntry==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //搜索时要把搜索记录记录到搜索记录表
        if (dto.getFromIndex()==0){
            this.insert(behaviorEntry.getEntryId(),dto.getSearchWords());
        }

        List<Map> list=new ArrayList<>();
        try {
            //构建搜索请求对象,指定索引库名称
            SearchRequest searchRequest = new SearchRequest("app_info_article");
            //条件构造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

            //根据关键字分词查询 title content 使用QueryStringQueryBuilder
            //按照dto关键字匹配title or context 来查询
            //select * from table where(title=? or content=?),publishTime<前台传入的时间;
            QueryStringQueryBuilder queryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords()).field("title").field("content").defaultOperator(Operator.OR);
            //两个查询条件关联
            boolQueryBuilder.must(queryBuilder);
            //发布时间小于当前时间
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime());
            //过滤条件
            boolQueryBuilder.filter(rangeQueryBuilder);
            //放到构造器中
            searchSourceBuilder.query(boolQueryBuilder);
            //按照发布时间倒叙查询
            searchSourceBuilder.sort("publishTime", SortOrder.DESC);
            //分页
            searchSourceBuilder.from(dto.getPageNum());//当前页码
            searchSourceBuilder.size(5);//显示几行
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //封装
            //把结果get出来 循环转成map 创建list 放到list里
            SearchHit[] hits = searchResponse.getHits().getHits();
            for (SearchHit hit : hits) {
                String sourceAsString = hit.getSourceAsString();
                Map map = JSON.parseObject(sourceAsString, Map.class);
                list.add(map);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return ResponseResult.okResult(list);
    }

    @Override
    public ResponseResult findUserSearch(UserSearchDto dto) {
        if (dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //获取本地线程中的用户user
        ApUser user = AppThreadLocalUtils.getUser();
        if (user==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"先去登录");
        }
        //远程调用 behavior 获取entryId
        ApBehaviorEntry behaviorEntry = behaviorFeign.findByUserIdOrEquipmentId(user.getId(), dto.getEquipmentId());
        if (behaviorEntry==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //分页
        IPage pageparam = new Page(dto.getPageNum(), dto.getPageSize());
        IPage result = page(pageparam, Wrappers.<ApUserSearch>lambdaQuery()
                .eq(ApUserSearch::getEntryId, behaviorEntry.getId())
                .eq(ApUserSearch::getStatus, 1));
        return ResponseResult.okResult(result.getRecords());
    }

    @Override
    public ResponseResult delUserSearch(UserSearchDto dto) {
        //校验参数
        if (dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //删除 逻辑删除 执行update status 0无效 1有效
        update(Wrappers.<ApUserSearch>lambdaUpdate()
                .eq(ApUserSearch::getId,dto.getId())
                .set(ApUserSearch::getStatus,0));
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    @Async("taskExecutor")//异步调用 跟线程池配置类里同名
    public void insert(Integer entryId, String searchWords) {
        //校验参数
        if (entryId==null|| StringUtils.isBlank(searchWords)){
            return;
        }
        //查询 去重
        ApUserSearch apUserSearch = this.getOne(Wrappers.<ApUserSearch>lambdaQuery()
                .eq(ApUserSearch::getEntryId, entryId)
                .eq(ApUserSearch::getKeyword, searchWords));
        //有 且 status=0 update 1 ;有 且 status=1 return
        if (apUserSearch!=null){
            if (apUserSearch.getStatus()==0){
                apUserSearch.setStatus(1);
                updateById(apUserSearch);
            }
            if (apUserSearch.getStatus()==1){
                return;
            }
        }else {
            //3.如果不存在，保存新的数据
            apUserSearch = new ApUserSearch();
            apUserSearch.setEntryId(entryId);
            apUserSearch.setStatus(1);
            apUserSearch.setKeyword(searchWords);
            apUserSearch.setCreatedTime(new Date());
            save(apUserSearch);
        }
    }
}
